package com.t3go.t3_map.service;

import androidx.annotation.NonNull;

import com.t3map.api.fence.IT3FenceService;
import com.t3map.api.fence.T3Fence;
import com.t3map.api.fence.entity.IT3AreaCircle;
import com.t3map.api.fence.entity.IT3AreaPolygon;
import com.t3map.api.fence.entity.IT3FenceArea;
import com.t3map.api.fence.entity.IT3FenceBlock;
import com.t3map.api.fence.entity.IT3FenceSpot;
import com.t3map.api.map.T3Map;
import com.t3map.api.map.model.T3LatLng;
import com.t3map.api.map.utils.T3MapUtils;

import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;


public class FenceService<T extends IT3FenceArea<P, C, B, S>,
        P extends IT3AreaPolygon, C extends IT3AreaCircle, B extends IT3FenceBlock, S extends IT3FenceSpot>
        implements IT3FenceService<T, P, C, B, S> {

    private T3Map mT3Map;

    /**
     * 围栏列表
     */
    private final List<T3Fence> fenceList = new ArrayList<>();
    /**
     * 现在正在显示的围栏
     */
    private T3Fence currentFence;

    private int fillColor;
    private int strokeColor;
    private boolean setColor;

    @Override
    public void init(T3Map t3Map) {
        mT3Map = t3Map;
    }

    @Override
    public void setData(List<T> list) {
        if (list == null || list.size() == 0) {
            hideAllFence();
            fenceList.clear();
            return;
        }

        hideAllFence();
        fenceList.clear();

        for (T area : list) {
            if (area == null) {
                continue;
            }
            T3Fence<T, P, C, B, S> fence = new T3Fence<>(area);
            if (setColor) {
                fence.setColor(fillColor, strokeColor);
            }
            fenceList.add(fence);
        }
    }

    @Override
    public void setFenceColor(int fillColor, int strokeColor) {
        this.fillColor = fillColor;
        this.strokeColor = strokeColor;
        this.setColor = true;
        for (T3Fence<T, P, C, B, S> fence : fenceList) {
            fence.setColor(fillColor, strokeColor);
        }
    }

    @Override
    public boolean fenceContainsPoint(@NonNull T3LatLng currentPoint) {

        return fenceContainsPoint(currentPoint, null);
    }

    @Override
    public boolean fenceContainsPoint(@NonNull @NotNull T3LatLng currentPoint, IContainExtra<T> containExtra) {
        T3Fence<T, P, C, B, S> t3Fence = findPointInFence(currentPoint);
        if (containExtra != null) {
            return t3Fence != null && containExtra.extraContainCondition(t3Fence.getFenceArea());
        }
        return t3Fence != null;
    }

    @Override
    public IT3FenceArea<P, C, B, S> showFence(T3LatLng currentPoint, IFenceVisibleCallBack<T> callBack) {
        T3Fence<T, P, C, B, S> t3Fence = findNearestFence(currentPoint);

        //如果要显示的围栏和上一个显示的围栏，不是同一个围栏，则先隐藏上一个围栏
        if (t3Fence != null && t3Fence.getId() != null && currentFence != null && !t3Fence.getId().equals(currentFence.getId())) {
            currentFence.hideFence();
        }
        currentFence = t3Fence;
        if (t3Fence == null) {
            return null;
        }

        //该点在电子围栏内
        if (!t3Fence.isShowing()) {
            //该围栏没有展示
            t3Fence.showFence(mT3Map);
            if (callBack != null) {
                callBack.onVisibleChange(t3Fence.getFenceArea(), true);
            }
        } else {
            if (callBack != null) {
                callBack.isShowed(t3Fence.getFenceArea());
            }
        }
        return t3Fence.getFenceArea();
    }

    @Override
    public void showAllFence() {
        for (T3Fence<T, P, C, B, S> fence : fenceList) {
            fence.showFence(mT3Map);
        }

    }

    @Override
    public void hideAllFence() {
        for (T3Fence<T, P, C, B, S> fence : fenceList) {
            fence.hideFence();
        }
        currentFence = null;
    }

    @Override
    public void lineAndAttach(T3LatLng currentPoint, B block, boolean isAttach, IAttachCallBack<S> callback) {
        if (currentFence != null) {
            currentFence.lineAndAttach(mT3Map, currentPoint, block, isAttach, callback);
        }
    }

    /**
     * 找到目标点所属的围栏，如果没有返回null
     *
     * @param currentPoint 分标点
     * @return 返回当前点所属的围栏，否则null
     */
    private T3Fence<T, P, C, B, S> findPointInFence(@NonNull T3LatLng currentPoint) {
        for (T3Fence<T, P, C, B, S> fence : fenceList) {
            if (fence == null || fence.getFenceArea() == null) {
                continue;
            }

            //是否在多边形区域内
            List<P> polygonList = fence.getFenceArea().getPolygonAreaList();
            if (polygonList != null) {
                for (P polygonArea : polygonList) {
                    if (polygonArea == null) {
                        continue;
                    }

                    if (T3MapUtils.isPolyHoleContainersPoint(polygonArea.getOutPointList(), polygonArea.getHoleList(), currentPoint)) {
                        return fence;
                    }
                }

            }

            //是否在圆形区域内
            List<C> circleList = fence.getFenceArea().getCircleAreaList();
            if (circleList != null) {
                for (C circleArea : fence.getFenceArea().getCircleAreaList()) {
                    if (circleArea == null) {
                        continue;
                    }

                    if (T3MapUtils.isCircleContainsPoint(circleArea.getCenter(), circleArea.getRadius(), currentPoint)) {
                        return fence;
                    }
                }
            }

            //是否是围栏内的上下车点
            if (isT3FenceSpot(currentPoint, fence.getFenceArea())) {
                return fence;
            }

        }
        return null;
    }

    private T3Fence<T, P, C, B, S> findNearestFence(@NonNull T3LatLng currentPoint) {

        float minDistance = Integer.MAX_VALUE;
        T3Fence<T, P, C, B, S> nearestArea = null;

        for (T3Fence<T, P, C, B, S> fence : fenceList) {
            if (fence == null || fence.getFenceArea() == null) {
                continue;
            }


            //是否在多边形区域内
            List<P> polygonList = fence.getFenceArea().getPolygonAreaList();
            if (polygonList != null) {
                for (P polygonArea : polygonList) {
                    if (polygonArea == null) {
                        continue;
                    }

                    if (T3MapUtils.isPolyHoleContainersPoint(polygonArea.getOutPointList(), polygonArea.getHoleList(), currentPoint)) {
                        return fence;
                    }
                }
            }

            //是否在圆形区域内
            List<C> circleList = fence.getFenceArea().getCircleAreaList();
            if (circleList != null) {
                for (C circleArea : fence.getFenceArea().getCircleAreaList()) {
                    if (circleArea == null) {
                        continue;
                    }

                    if (T3MapUtils.isCircleContainsPoint(circleArea.getCenter(), circleArea.getRadius(), currentPoint)) {
                        return fence;
                    }
                }
            }

            //是否是围栏内的上下车点
            float minAreaDistance = Float.MAX_VALUE;
            for (S point : fence.getFenceArea().getRealPointList()) {
                if (point == null) {
                    continue;
                }

                float distance = T3MapUtils.calculateLineDistance(new T3LatLng(point.getLatitude(), point.getLongitude()), currentPoint);
                if (distance != -1 && distance < 1) {
                    return fence;
                }

                if (distance < minAreaDistance) {
                    minAreaDistance = distance;
                }
            }

            if (minAreaDistance < minDistance) {
                minDistance = minAreaDistance;
                nearestArea = fence;
            }
        }

        return nearestArea;
    }


    // 是否是围栏点，因为有些围栏点是在围栏外部
    private boolean isT3FenceSpot(T3LatLng currentPoint, T area) {
        if (area == null || area.getRealPointList() == null) {
            return false;
        }

        for (S point : area.getRealPointList()) {
            if (point == null) {
                continue;
            }

            float distance = T3MapUtils.calculateLineDistance(new T3LatLng(point.getLatitude(), point.getLongitude()), currentPoint);
            if (distance != -1 && distance < 1) {
                return true;
            }
        }
        return false;
    }

    public boolean isShowing() {
        return currentFence != null && currentFence.isShowing();
    }
}
